#include "stdafx.h"
#include "CScrLanguage.h"

CList<const CConstant<int>>			CConstants::s_pConstantList;
CList<const CConstant<int>>			CConstants::s_pConstantFileList;
CList<const CConstant<int>>			CConstants::s_pConstantModelList;
CLListEx<class CIdentifier const*>	CConstants::s_pScriptIdentifiers;
int									CConstants::s_nNumConstants = 0;
int									CConstants::s_nNumFileConstants = 0;
int									CConstants::s_nNumFileEnumerators = 0;
int									CConstants::s_nNumModelConstants = 0;
int									CConstants::s_nNumScriptConstants = 0;
int									CConstants::s_nNumScriptEnumerators = 0;
const CConstant<int>			**	CConstants::s_pModelsList = nullptr;
int									CEnums::s_nNumEnums = 0;

bool CConstants::LoadFromFile(const char *szFilePath)
{
	if(FILE *hFile = OpenFile(szFilePath, "rt"))
	{
		try
		{
			CEnum * pEnum;
			auto pType = CSyntax::GetType(TYPE_INT);
			bool bInEnum = false;

			while(char *szStr = GetConfigLine(hFile))
			{
				char * szTok = szStr;

				while(*szTok)
				{
					while(*szTok && (IsIdentifierChar(*szTok) || IsSpace(*szTok)))
					{
						if(IsSpace(*szTok)) *szTok = '\0';
						++szTok;
					}

					switch(*szTok)
					{
					case '{':
						if(bInEnum) throw(SCRambl.GetText("CONSTANTS", "M100"));
						if(!*szStr) throw(SCRambl.GetText("CONSTANTS", "M101"));
						pEnum = CEnums::Add(szStr);
						bInEnum = true;
						++szTok;
						++szStr;
						continue;
					case '}':
						if(!pEnum) throw(SCRambl.GetText("CONSTANTS", "M102"));
						bInEnum = false;
						szStr = szTok + 1;
						while(*szStr && IsSpace(*szStr)) *szStr++ = '\0';
						szTok = szStr;
						while(*szStr && !IsSpace(*szStr)) ++szStr;
						*szStr = '\0';
						if(*szTok) CSyntax::AddEnum(szTok, pEnum);
						szTok = szStr;
						continue;
					case '\0':
						if(bInEnum) CConstants::AddFromFile(pEnum->Add(szStr));
						else
						{
							for(; szTok[-1]; --szTok);
							if(IsStringInt(szTok)) CConstants::AddFromFile(szStr, StringToInt(szTok));
							else if(CIdentifiers::IsValidIdentifier(szTok))
							{
								if(auto pConst = Get(szTok))
								{
									if(pConst->IsEnumerator())
									{
										auto pEnum = pConst->Enumerate()->GetEnum();
										Add(new CEnumerator(szStr, pConst->GetValue(), pEnum));
									}
									else CConstants::AddFromFile(szStr, pConst->GetValue());
								}
								else throw(SCRambl.BuildText(SCRambl.GetText("CONSTANTS", "M103"), NULL, 0, "%s%s", szTok, szStr));
							}
							else throw(SCRambl.BuildText(SCRambl.GetText("CONSTANTS", "M104"), NULL, 0, "%s%s", szTok, szStr));
						}
						break;
					default: break;
					}
					break;
				}
			}
			CloseFile(hFile);
			return true;
		}
		catch(const char *e)
		{
			CloseFile(hFile);
			throw(SCRambl.BuildText(SCRambl.GetText("GENERAL", "FERR"), NULL, 0, "%s%s", e, szFilePath));
		}
	}
	else throw(SCRambl.BuildText(SCRambl.GetText("GENERAL", "OERR"), NULL, 0, "%s", szFilePath));
	return false;
}
bool CConstants::LoadDatFile(const char * szFilePath)
{
	// Load IDE files through gta.dat, default.dat...
	if(FILE *hFile = OpenFile(szFilePath, "r"))
	{
		try
		{
			// chdir to GTASA install
			SCRambl.ChangeCurrentDirectory(CURRENT_DIR_INSTALL);
		
			// Do things the GTA way
			while(char *str = SCRambl.ReadConfigLine(hFile))
			{
				if(*str == '#') continue;
				if((str = strtok(str, " \t,()")) && !stricmp(str, "ide"))
				{
					if((str = strtok(nullptr, " \t,()")))
					{
						if(!strnicmp(str, "data", 4))
							LoadIdeFile(str, true);
					}
				}
			}

			SCRambl.ResetCurrentDirectory();
			CloseFile(hFile);
			return true;
		}
		catch(const char *e)
		{
			CloseFile(hFile);
			SCRambl.ResetCurrentDirectory();
			throw(SCRambl.BuildText(SCRambl.GetText("GENERAL", "FERR"), NULL, 0, "%s%s", e, szFilePath));
		}
	}
	else throw(SCRambl.BuildText(SCRambl.GetText("GENERAL", "OERR"), NULL, 0, "%s", szFilePath));
	return false;
}
bool CConstants::LoadIdeFile(const char * szFilePath, bool bIsMapFile)
{
	// Load model constants in IDE file
	char szPath[MAX_PATH];
	szncpy(szPath, szFilePath, sizeof(szPath));
	if(FILE *hFile = OpenFile(szPath, "r"))
	{
		int nNumLines = 0;
		try
		{
			char * str;
			bool bInObjs = false;
			while(str = SCRambl.ReadConfigLine(hFile))
			{
				++nNumLines;
				if(*str == '#') continue;
				if((str = strtok(str, " \t,()")))
				{
					if(!stricmp(str, "objs") || !stricmp(str, "tobj"))
						bInObjs = true;
					else if(!bIsMapFile)
						ParseIdeLine(str);
					else if(bInObjs)
					{
						if(!stricmp(str, "end")) bInObjs = false;
						else ParseIdeLine(str);
					}
				}
			}
			CloseFile(hFile);
			return true;
		}
		catch(const char *e)
		{
			char szError[256];
			CloseFile(hFile);
			SCRambl.ResetCurrentDirectory();
			szncpy(szError, e, sizeof(szError));
			THROW("%s(%d) : %s", szPath, nNumLines, szError);
		}
	}
	else THROW("Failed to open IDE file '%s'", szPath);
	return false;
}

bool CConstants::ParseIdeLine(char *szStr)
{
	// Load a model constant from a line in the IDE file
	if(IsStringInt(szStr))
	{
		int id = StringToInt(szStr);
		if(szStr = strtok(nullptr, " \t,()"))
		{
			for(int i=0; szStr[i]; ++i) if(szStr[i] == '+' || szStr[i] == '-') szStr[i] = '_';
			if(IsDecimal(*szStr)) *--szStr = '_';
			AddForModel(szStr, id);
			return true;
		}
	}
	return false;
}